#pragma once

#include "./include/t3sdk.h"

#include <string>

#include <nlohmann/json.hpp>

#include <fmt/format.h>

using nlohmann::json;
using namespace t3sdk;

namespace HST3
{
    struct CommonHead
    {
        std::string Function;
        std::string Service;
        std::string ShardingInfo;
    };

    struct Security
    {
        // 账号密码
        std::string pwd_auth_shadow;
        // 密码类别
        std::string pwd_auth_type;

        // 登录后返回
        std::string authid_str_respheader;
        std::string righttype_str_respheader;
        std::string user_token;
    };

    class Request
    {
    public:
        Request()
        {
            m_Message = NewMessage(MessageType::HSRequest);
            m_Message->AddRef();
        }
        ~Request()
        {
            if (m_Message != nullptr)
            {
                m_Message->Release();
                m_Message = nullptr;
            }
        }

        void ClearParam()
        {
            if (m_Message != nullptr)
            {
                m_Message->ReSet();
            }
        }

        void SetHead(const CommonHead &head, const Security &security)
        {
            if (head.Function.empty() || head.Service.empty())
            {
                return;
            }
            m_Message->SetMessageType(HSRequest);
            m_Message->SetFunction(head.Function.c_str());
            m_Message->SetService(head.Service.c_str());

            // 格式 {"cust_id": "11111"}
            json jstr;
            jstr["cust_id"] = head.ShardingInfo;
            /*
            static const std::string tFmt = R"("cust_id" : "{}")";
            std::string msg = "{";
            msg.append(std::move(fmt::format(tFmt, ToCstr(head.ShardingInfo))));
            msg.push_back('}');

            m_Message->SetShardingInfo(msg.c_str());
            */
            std::string tmp = jstr.dump();
            m_Message->SetShardingInfo(tmp.c_str());

            if (!security.pwd_auth_shadow.empty())
                SetSecurity(security);
        }

        template <typename ValueType>
        void AddParam(std::string &&name, ValueType &&value)
        {
            m_Params[name] = std::forward<ValueType>(value);
        }

        /*
        void AddParam(std::string &&name, const char *value)
        {
            m_Params[name] = value;
        }

        void AddParam(std::string &&name, const std::string& value)
        {
            m_Params.at(std::forward<std::string>(name)) = value;
            //m_Params[name] = value;
        }
        */

        void EndAddParam()
        {
            std::string paramstr = m_Params.dump();

            fmt::print("EndAddParam: {}\n", paramstr);
            m_Message->SetBody((void *)paramstr.c_str(), paramstr.size());

            m_Params.clear();
        }

        std::pair<void *, int> SerialStr()
        {
            int length = 0;
            void *ptr = m_Message->GetBuff(length);
            return std::make_pair(ptr, length);
        }

    private:
        void SetSecurity(const Security &security)
        {
            static const std::string tFmt = R"("pwd_auth_shadow":"{}", "pwd_auth_type":"{}", "authid_str_respheader":"{}","righttype_str_respheader":"{}","user_token":"{}")";

            auto securityStr = fmt::format(tFmt,
                                           ToCstr(security.pwd_auth_shadow),
                                           ToCstr(security.pwd_auth_type),
                                           ToCstr(security.authid_str_respheader),
                                           ToCstr(security.righttype_str_respheader),
                                           ToCstr(security.user_token));

            std::string msg = "{";
            msg.append(std::move(securityStr));
            msg.push_back('}');

            m_Message->SetSecurity(msg.c_str());
        }

        const char *ToCstr(const std::string &str)
        {
            return str.empty() ? "" : str.c_str();
        };

    private:
        // Document m_DocParam;

        json m_Params;

        IT3Message *m_Message = nullptr;
    };
}